#ifndef lint
static const char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
#endif

#define YYBYACC 1
#define YYMAJOR 1
#define YYMINOR 9

#define YYEMPTY        (-1)
#define yyclearin      (yychar = YYEMPTY)
#define yyerrok        (yyerrflag = 0)
#define YYRECOVERING() (yyerrflag != 0)

#define YYPREFIX "yy"

#define YYPURE 0

#line 2 "parser/yacc/gramatica.y"
#include "functionparser.h"

const char *str;
NOfundef *no;
/* Lista de strings para deletar ao final do parsing:*/
linkedlist listalixo;
/* "palavra":*/
char palavra[STRING_TAMMAX];
/* "vars":*/
char vars[VALORES_TAMANHO+1];/*Um espaço a mais para o "\0".*/
/* "funimpl":*/
funimpl implauxtemp;
funimpl implaux[VALORES_TAMANHO];
unsigned int implaux_indice;
/* "funrec_base_impl"*/
VALORES_TIPO valoraux;
/* "funrec_passo_def"*/
char *funrec_passo_def[2];
/* "funnome":*/
char *funnome_ultimo;

extern int yylex(void);
static void yyerror(const char *s);
#line 29 "parser/yacc/gramatica.y"
#ifdef YYSTYPE
#undef  YYSTYPE_IS_DECLARED
#define YYSTYPE_IS_DECLARED 1
#endif
#ifndef YYSTYPE_IS_DECLARED
#define YYSTYPE_IS_DECLARED 1
typedef union
{
	char          caractere;
	unsigned int  natural;
	funnome_dados fnome;
} YYSTYPE;
#endif /* !YYSTYPE_IS_DECLARED */
#line 56 "parser/functionparser.c"

/* compatibility with bison */
#ifdef YYPARSE_PARAM
/* compatibility with FreeBSD */
# ifdef YYPARSE_PARAM_TYPE
#  define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM)
# else
#  define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM)
# endif
#else
# define YYPARSE_DECL() yyparse(void)
#endif

/* Parameters sent to lex. */
#ifdef YYLEX_PARAM
# define YYLEX_DECL() yylex(void *YYLEX_PARAM)
# define YYLEX yylex(YYLEX_PARAM)
#else
# define YYLEX_DECL() yylex(void)
# define YYLEX yylex()
#endif

/* Parameters sent to yyerror. */
#ifndef YYERROR_DECL
#define YYERROR_DECL() yyerror(const char *s)
#endif
#ifndef YYERROR_CALL
#define YYERROR_CALL(msg) yyerror(msg)
#endif

extern int YYPARSE_DECL();

#define LETRA 257
#define VARNOME 258
#define DIGITO 259
#define YYERRCODE 256
static const short yylhs[] = {                           -1,
    0,    0,    0,    0,    0,    6,    7,    7,    8,    9,
   11,   11,   14,   14,    3,    4,    5,    5,    2,    2,
   10,   10,   13,   13,    1,    1,   12,   12,
};
static const short yylen[] = {                            2,
    3,    6,    3,    3,    1,    5,    1,    1,    6,    7,
    0,    2,    0,    2,    4,    4,    1,    3,    1,    5,
    1,    2,    1,    3,    1,    2,    1,    2,
};
static const short yydefred[] = {                         0,
    5,   21,    0,    0,    0,    0,    0,    0,    0,    0,
   22,    0,    0,    0,    1,    0,   27,    0,    7,    3,
    0,    0,    4,   23,    0,    0,    0,    0,    0,   28,
    0,    0,   15,    0,    0,   25,    0,   17,    0,    0,
    0,    6,    0,   24,   26,    0,    2,    0,   16,    0,
    0,    9,    0,   18,    0,    0,    0,    0,    0,    0,
   10,    0,
};
static const short yydgoto[] = {                          3,
   37,   18,    4,   15,   39,    5,   20,    6,   23,   16,
   25,   21,   40,   58,
};
static const short yysindex[] = {                      -235,
    0,    0,    0,  -47,  -35,  -32,  -40, -230, -240, -230,
    0, -228,  -67,   -9,    0, -225,    0,   -6,    0,    0,
 -226,   -5,    0,    0, -223,  -34, -222, -234, -228,    0,
 -220,   -2,    0, -219, -217,    0,  -92,    0,  -33,  -29,
   -1,    0,    1,    0,    0, -222,    0, -230,    0, -217,
 -213,    0, -212,    0,    2,  -39, -228,    7, -228,    5,
    0,  -28,
};
static const short yyrindex[] = {                         0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0, -208,  -38,    0,    0,   13,    0,    0,    0,    0,
   54,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0, -203,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,   17,    0,   18,    0,    0,    0,    0,   19,
    0,    0,
};
static const short yygindex[] = {                         0,
   12,   10,   11,   -3,    0,    0,    0,    0,    0,    4,
    0,    0,   -7,    0,
};
#define YYTABLESIZE 219
static const short yytable[] = {                         12,
   59,   21,   46,    7,   26,   19,   33,   47,   34,   35,
   48,   49,   33,    8,   50,   50,   13,   14,   17,   22,
    1,    2,   13,   24,   38,    9,   13,   27,   10,   24,
   28,   11,   30,   29,   31,   32,   36,   41,   42,   43,
   44,   52,   51,    2,   54,   57,   45,   61,   50,   60,
   11,   62,   19,    8,   56,   12,   20,   53,   13,   14,
    0,   55,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,   45,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
    0,    0,    0,    0,    0,    0,   11,   11,   21,
};
static const short yycheck[] = {                         40,
   40,   40,   95,    0,   12,    9,   41,   41,   43,   44,
   44,   41,   41,   61,   44,   44,  257,    8,  259,   10,
  256,  257,  257,  258,   28,   61,  257,   95,   61,  258,
   40,  257,  259,   40,   40,  259,  259,  258,   41,  259,
  258,   41,   44,  257,   48,   44,  259,   41,   44,   57,
  259,   59,   40,    0,   51,  259,   40,   46,   41,   41,
   -1,   51,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,  259,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
   -1,   -1,   -1,   -1,   -1,   -1,  257,  257,  257,
};
#define YYFINAL 3
#ifndef YYDEBUG
#define YYDEBUG 0
#endif
#define YYMAXTOKEN 259
#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? (YYMAXTOKEN + 1) : (a))
#if YYDEBUG
static const char *yyname[] = {

"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,"'('","')'",0,"'+'","','",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'='",0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'_'",0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"LETRA",
"VARNOME","DIGITO","illegal-symbol",
};
static const char *yyrule[] = {
"$accept : igualdade",
"igualdade : fundef '=' funimpl",
"igualdade : fundef '=' funnome '(' internas ')'",
"igualdade : funrec_base_def '=' funrec_base_impl",
"igualdade : funrec_passo_def '=' funrec_passo_impl",
"igualdade : error",
"funrec_base_def : palavra '(' varspre DIGITO ')'",
"funrec_base_impl : funimpl",
"funrec_base_impl : valor",
"funrec_passo_def : palavra '(' vars '+' DIGITO ')'",
"funrec_passo_impl : funnome '(' VARNOME ',' fundef varspos ')'",
"varspre :",
"varspre : vars ','",
"varspos :",
"varspos : ',' vars",
"fundef : palavra '(' vars ')'",
"funimpl : funnome '(' vars ')'",
"internas : funimpl",
"internas : internas ',' funimpl",
"funnome : palavra",
"funnome : LETRA '_' numero '_' numero",
"palavra : LETRA",
"palavra : palavra LETRA",
"vars : VARNOME",
"vars : vars ',' VARNOME",
"numero : DIGITO",
"numero : numero DIGITO",
"valor : DIGITO",
"valor : valor DIGITO",

};
#endif

int      yydebug;
int      yynerrs;

int      yyerrflag;
int      yychar;
YYSTYPE  yyval;
YYSTYPE  yylval;

/* define the initial stack-sizes */
#ifdef YYSTACKSIZE
#undef YYMAXDEPTH
#define YYMAXDEPTH  YYSTACKSIZE
#else
#ifdef YYMAXDEPTH
#define YYSTACKSIZE YYMAXDEPTH
#else
#define YYSTACKSIZE 10000
#define YYMAXDEPTH  10000
#endif
#endif

#define YYINITSTACKSIZE 200

typedef struct {
    unsigned stacksize;
    short    *s_base;
    short    *s_mark;
    short    *s_last;
    YYSTYPE  *l_base;
    YYSTYPE  *l_mark;
} YYSTACKDATA;
/* variables for the parser stack */
static YYSTACKDATA yystack;
#line 493 "parser/yacc/gramatica.y"
 /*** *** *** Funções do parser *** *** ***/

// --- "palavra" --------------------------------------------------------
void reset_palavra(void)
{
	palavra[0] = '\0';
}

void palavra_append(char c)
{
	unsigned int n = strlen(palavra);
	if (n >= STRING_TAMMAX) return;
	palavra[n] = c;
	palavra[n+1] = '\0';
}

void palavra_append_num(unsigned int n)
{
	if ((n/10) != 0) palavra_append_num(n/10);
	palavra_append((n%10)+'0');
}

// --- "vars" -----------------------------------------------------------
void reset_vars(void)
{
	vars[0] = '\0';
}

bool var_append(char c)
{
	// Verifica se a variável "c" já está no conjunto.
	// Ou seja: checa se ela já está "declarada"!
    if (strchr(vars,c)) return(false);
    unsigned int n = strlen(vars);
    if (n >= VALORES_TAMANHO) return (false);
    vars[n] = c;
    vars[n+1] = '\0';
    return(true);
}

void var_placeholder(void)
{
	if (implaux_indice > VALORES_TAMANHO) return;
	unsigned int i=0;
	while (i < implaux_indice) vars[i++] = VARS_PLACEHOLDER;
	vars[i] = '\0';
}

// --- "funimpl" --------------------------------------------------------
bool implaux_append(funimpl fi)
{
	// Checar se extrapolou o número máximo de implementações:
	if (implaux_indice >= VALORES_TAMANHO) return(false);
	implaux[implaux_indice] = fi;
	implaux_indice++;
	return(true);
}

funimpl implaux_pop(void)
{
	funimpl fi;
	fi.tipo = -1;
	fi.impl = NULL;
	if (implaux_indice)
	{
		fi = implaux[implaux_indice-1];
		implaux_indice--;
	}
	return(fi);
}

void implaux_clear(void)
{
	unsigned int i;
	for (i=0 ; i<implaux_indice ; i++)
		funimpl_del(implaux[i]);
	implaux_indice = 0;
}

// Checar se a função PR representada pelo nome "n" e pelo array de variáveis "v"
// é uma das primitivas "Z" ou "S" ou uma Função Geral:
funtipo funcao_Z_S_GERAL(const char *n, const char *v)
{
	if (!n || !v) return(-1);
	if (!strcmp(n,"Z") && (strlen(v) == 1)) return(ZERO_FUNCTION);
	if (!strcmp(n,"S") && (strlen(v) == 1)) return(SUCCESSOR_FUNCTION);
	return(GENERAL_FUNCTION);
}

// --- "funnome" --------------------------------------------------------
funimpl gerar_funimpl(funnome_dados fn)
{
	if (fn.tipo == PROJECTION_FUNCTION)
	{
		#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
			printf("[DEBUG]   + nome: {%s}\n",fn.projecao.nome);
			printf("[DEBUG]   + i   : {%u}\n",fn.projecao.i);
			printf("[DEBUG]   + n   : {%u}\n",fn.projecao.n);
			printf("[DEBUG]   + vars: (");var_print(vars);printf(")\n");
		#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
		return(funimpl_novo_projecao(fn.projecao.nome,vars,fn.projecao.i));
	}
	else
	{
		#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
			printf("[DEBUG]   + nome: {%s}\n",fn.nome);
			printf("[DEBUG]   + vars: (");var_print(vars);printf(")\n");
		#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
		return(funimpl_novo(funcao_Z_S_GERAL(fn.nome,vars),fn.nome,vars));
	}
}

bool projecao_indice(funnome_dados fn, unsigned int a)
{
	if ((fn.tipo == PROJECTION_FUNCTION) && (fn.projecao.n != a)) return(true);
	return(false);
}

// --- Funções básicas do Yacc ------------------------------------------
NOfundef* analisar(const char *s)
{
	str = s;
	no = NULL;
	linkedlist_init(&listalixo,NO_STRING);
	reset_palavra();
	reset_vars();
	implauxtemp.tipo = -1;
	implauxtemp.impl = NULL;
	implaux_indice = 0;
	valoraux = 0;
	funrec_passo_def[0] = NULL;
	funrec_passo_def[1] = NULL;
	funnome_ultimo = NULL;
	#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
		printf("\n[DEBUG] *** *** *** \"yyparse()\" : INICIO *** *** ***\n");
	#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
	// Se ocorrer algum erro no parsing...
	if (yyparse())
	{
		// Desalocar o "no" e setá-lo para NULL:
		fundef_del(no);
		no = NULL;
		// Desalocar quaisquer elementos no vetor de implementações:
		implaux_clear();
	}
	#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
		printf("[DEBUG] Lista de strings temporarias:\n");
		llno *p = listalixo.inicio;
		while(p)
		{
			printf("[DEBUG] * \"%s\"\n",p->valor.s);
			p = p->prox;
		}
	#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
	// Desalocar lista de strings temporárias:
	linkedlist_clear(&listalixo);
	#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
		printf("\n[DEBUG] *** *** *** \"yyparse()\" : FIM *** *** ***\n");
	#endif //DEBUG_FUNCTIONPARSER_GRAMATICA
	return(no);
}

static void yyerror(const char *s)
{
	//fprintf(stderr, "%s\n", s);
}

int yylex(void)
{
	int c = *str;
	// Checar se o caractere lido é um dos caracteres extras para o nome de função:
	bool is_extra = false;
	if ((*str != '\0') && strchr(FUNNOME_CARACTERES_EXTRAS,*str)) is_extra = true;
	// Incrementar o ponteiro da string de entrada (se o caractere atual NÃO for um '\0'):
	if (*str) str++;
	// Se for uma letra maiúscula:
	if ((isalpha(c) && isupper(c)) || is_extra)
	{
		yylval.caractere = c;
		return(LETRA);
	}
	// Se for uma letra minúscula:
	if (isalpha(c) && islower(c))
	{
		yylval.caractere = c;
		return(VARNOME);
	}
	// Se for um dígito:
	if (isdigit(c))
	{
		yylval.natural = c - '0';
		return(DIGITO);
	}
	return(c);
}
#line 467 "parser/functionparser.c"

#if YYDEBUG
#include <stdio.h>		/* needed for printf */
#endif

#include <stdlib.h>	/* needed for malloc, etc */
#include <string.h>	/* needed for memset */

/* allocate initial stack or double stack size, up to YYMAXDEPTH */
static int yygrowstack(YYSTACKDATA *data)
{
    int i;
    unsigned newsize;
    short *newss;
    YYSTYPE *newvs;

    if ((newsize = data->stacksize) == 0)
        newsize = YYINITSTACKSIZE;
    else if (newsize >= YYMAXDEPTH)
        return -1;
    else if ((newsize *= 2) > YYMAXDEPTH)
        newsize = YYMAXDEPTH;

    i = (int) (data->s_mark - data->s_base);
    newss = (short *)realloc(data->s_base, newsize * sizeof(*newss));
    if (newss == 0)
        return -1;

    data->s_base = newss;
    data->s_mark = newss + i;

    newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs));
    if (newvs == 0)
        return -1;

    data->l_base = newvs;
    data->l_mark = newvs + i;

    data->stacksize = newsize;
    data->s_last = data->s_base + newsize - 1;
    return 0;
}

#if YYPURE || defined(YY_NO_LEAKS)
static void yyfreestack(YYSTACKDATA *data)
{
    free(data->s_base);
    free(data->l_base);
    memset(data, 0, sizeof(*data));
}
#else
#define yyfreestack(data) /* nothing */
#endif

#define YYABORT  goto yyabort
#define YYREJECT goto yyabort
#define YYACCEPT goto yyaccept
#define YYERROR  goto yyerrlab

int
YYPARSE_DECL()
{
    int yym, yyn, yystate;
#if YYDEBUG
    const char *yys;

    if ((yys = getenv("YYDEBUG")) != 0)
    {
        yyn = *yys;
        if (yyn >= '0' && yyn <= '9')
            yydebug = yyn - '0';
    }
#endif

    yynerrs = 0;
    yyerrflag = 0;
    yychar = YYEMPTY;
    yystate = 0;

#if YYPURE
    memset(&yystack, 0, sizeof(yystack));
#endif

    if (yystack.s_base == NULL && yygrowstack(&yystack)) goto yyoverflow;
    yystack.s_mark = yystack.s_base;
    yystack.l_mark = yystack.l_base;
    yystate = 0;
    *yystack.s_mark = 0;

yyloop:
    if ((yyn = yydefred[yystate]) != 0) goto yyreduce;
    if (yychar < 0)
    {
        if ((yychar = YYLEX) < 0) yychar = 0;
#if YYDEBUG
        if (yydebug)
        {
            yys = yyname[YYTRANSLATE(yychar)];
            printf("%sdebug: state %d, reading %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
    }
    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: state %d, shifting to state %d\n",
                    YYPREFIX, yystate, yytable[yyn]);
#endif
        if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack))
        {
            goto yyoverflow;
        }
        yystate = yytable[yyn];
        *++yystack.s_mark = yytable[yyn];
        *++yystack.l_mark = yylval;
        yychar = YYEMPTY;
        if (yyerrflag > 0)  --yyerrflag;
        goto yyloop;
    }
    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
    {
        yyn = yytable[yyn];
        goto yyreduce;
    }
    if (yyerrflag) goto yyinrecovery;

    yyerror("syntax error");

    goto yyerrlab;

yyerrlab:
    ++yynerrs;

yyinrecovery:
    if (yyerrflag < 3)
    {
        yyerrflag = 3;
        for (;;)
        {
            if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 &&
                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: state %d, error recovery shifting\
 to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]);
#endif
                if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack))
                {
                    goto yyoverflow;
                }
                yystate = yytable[yyn];
                *++yystack.s_mark = yytable[yyn];
                *++yystack.l_mark = yylval;
                goto yyloop;
            }
            else
            {
#if YYDEBUG
                if (yydebug)
                    printf("%sdebug: error recovery discarding state %d\n",
                            YYPREFIX, *yystack.s_mark);
#endif
                if (yystack.s_mark <= yystack.s_base) goto yyabort;
                --yystack.s_mark;
                --yystack.l_mark;
            }
        }
    }
    else
    {
        if (yychar == 0) goto yyabort;
#if YYDEBUG
        if (yydebug)
        {
            yys = yyname[YYTRANSLATE(yychar)];
            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
                    YYPREFIX, yystate, yychar, yys);
        }
#endif
        yychar = YYEMPTY;
        goto yyloop;
    }

yyreduce:
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
                YYPREFIX, yystate, yyn, yyrule[yyn]);
#endif
    yym = yylen[yyn];
    if (yym)
        yyval = yystack.l_mark[1-yym];
    else
        memset(&yyval, 0, sizeof yyval);
    switch (yyn)
    {
case 1:
#line 52 "parser/yacc/gramatica.y"
	{
				no->implementacao = implaux_pop();
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> fundef '=' funimpl\" foi reconhecido!\n");
					printf("[DEBUG] * no : {");
					fundef_print(no,0);
					printf("}\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* Verificar se a aridade da função e de sua implementação são iguais:*/
				if (fundef_aridade(no) != funimpl_aridade(no->implementacao))
				{
					ERRO_ARIDADE_DIFERENTE(no->nome,funimpl_get_nome(no->implementacao),fundef_aridade(no),funimpl_aridade(no->implementacao));
					YYABORT;
				}
				/* Verificar se os argumentos da função e de sua implementação são iguais (e se estão na mesma ordem):*/
				if (strcmp(no->variaveis,funimpl_get_variaveis(no->implementacao)))
				{
					ERRO_ARGUMENTOS_DIFERENTES(no->nome,funimpl_get_nome(no->implementacao));
					YYABORT;
				}
			}
break;
case 2:
#line 77 "parser/yacc/gramatica.y"
	{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> fundef '=' funnome '(' internas ')'\" foi reconhecido!\n");
					printf("[DEBUG] * Definicao:\n");
					printf("[DEBUG]   + nome : {%s}\n",no->nome);
					printf("[DEBUG]   + vars : (");var_print(no->variaveis);printf(")\n");
					printf("[DEBUG] * Funcao externa:\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* Caso "funnome" seja uma Projeção, verificar se o valor de seu índice "n"*/
				/* é igual a quantidade de funções internas da Composição:*/
				if (projecao_indice(yystack.l_mark[-3].fnome,implaux_indice))
				{
					ERRO_COMP_PROJECAO_LIMITE(yystack.l_mark[-3].fnome.projecao.n,implaux_indice);
					YYABORT;
				}
				var_placeholder();
				implauxtemp = gerar_funimpl(yystack.l_mark[-3].fnome);
				unsigned int i;
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("[DEBUG] * Funcao(oes) interna(s):\n");
					for (i=0 ; i<implaux_indice ; i++)
					{
						printf("[DEBUG]   + %u. ",i);
						funimpl_print(implaux[i]);
						printf("\n");
					}
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* Verificações de erros da definição da função em relação a cada função INTERNA da composição:*/
				for (i=0 ; i<implaux_indice ; i++)
				{
					/* Verificar se as aridades são iguais:*/
					if (fundef_aridade(no) != funimpl_aridade(implaux[i]))
					{
						ERRO_ARIDADE_DIFERENTE(no->nome,funimpl_get_nome(implaux[i]),fundef_aridade(no),funimpl_aridade(implaux[i]));
						YYABORT;
					}
					/* Verificar se os argumentos das funções são iguais (e se estão na mesma ordem):*/
					if (strcmp(no->variaveis,funimpl_get_variaveis(implaux[i])))
					{
						ERRO_ARGUMENTOS_DIFERENTES(no->nome,funimpl_get_nome(implaux[i]));
						YYABORT;
					}
				}
				/* Montar a struct da Composição:*/
				no->implementacao = funimpl_novo_composicao(implauxtemp,implaux,&implaux_indice);
			}
break;
case 3:
#line 128 "parser/yacc/gramatica.y"
	{
				implauxtemp = implaux_pop();
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> funrec_base_def '=' funrec_base_impl\" foi reconhecido!\n");
					printf("[DEBUG] * nome             : {%s}\n",no->nome);
					printf("[DEBUG] * vars             : (");var_print(no->variaveis);printf(")\n");
					printf("[DEBUG] * funrec_base_impl : {");funimpl_print(implauxtemp);printf("}\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* --- Caso -----*/
				/* * H(0) = k*/
				/* --------------*/
				if (fundef_aridade(no) == 1)
				{
					if (implauxtemp.tipo != CONSTANT_FUNCTION)
					{
						ERRO_RECURSAO_CONSTANTE_REQUERIDA(no->nome);
						funimpl_del(implauxtemp);
						YYABORT;
					}
				}
				/* --- Caso -------------------------------*/
				/* * H(x1, ..., xn, 0) = F(x1, ..., xn)*/
				/* ----------------------------------------*/
				else
				{
					if (implauxtemp.tipo == CONSTANT_FUNCTION)
					{
						ERRO_RECURSAO_CONSTANTE_PROIBIDA(no->nome);
						funimpl_del(implauxtemp);
						YYABORT;
					}
					if (fundef_aridade(no) != funimpl_aridade(implauxtemp) + 1)
					{
						ERRO_RECURSAO_ARIDADE_DIFERENTE(funimpl_get_nome(implauxtemp),funimpl_aridade(implauxtemp),no->nome,fundef_aridade(no));
						funimpl_del(implauxtemp);
						YYABORT;
					}
					if (strncmp(no->variaveis,funimpl_get_variaveis(implauxtemp),funimpl_aridade(implauxtemp)))
					{
						ERRO_ARGUMENTOS_DIFERENTES(no->nome,funimpl_get_nome(implauxtemp));
						funimpl_del(implauxtemp);
						YYABORT;
					}
				}
				/* Montar a struct da recursão (com o caso base apenas):*/
				no->implementacao = funimpl_novo_recursao(no,fundef_aridade(no),implauxtemp,RECURSAO_BASE);
			}
break;
case 4:
#line 177 "parser/yacc/gramatica.y"
	{
				/* --- Casos ------------------------------------------------------*/
				/* * H(x1, ..., xn, t+1) = G(t, H(x1, ..., xn, t), x1, ..., xn)*/
				/* * H(x1, ..., xn, t+1) = G(t, H(t))*/
				/* ----------------------------------------------------------------*/
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"igualdade ---> funrec_passo_def '=' funrec_passo_impl\" foi reconhecido!\n");
					printf("[DEBUG] * no : ");
					fundef_print(no,15);
					printf("\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				if (strcmp(funrec_passo_def[0],no->nome))
				{
					ERRO_RECURSAO_NOME_DIFERENTE(funrec_passo_def[0],no->nome);
					YYABORT;
				}
				if (strlen(funrec_passo_def[1]) != fundef_aridade(no))
				{
					ERRO_ARIDADE_DIFERENTE(funrec_passo_def[0],no->nome,strlen(funrec_passo_def[1]),fundef_aridade(no));
					YYABORT;
				}
				if (strcmp(funrec_passo_def[1],no->variaveis))
				{
					ERRO_ARGUMENTOS_DIFERENTES(funrec_passo_def[0],no->nome);
					YYABORT;
				}
			}
break;
case 5:
#line 205 "parser/yacc/gramatica.y"
	{ ERRO_SINTAXE; YYABORT; }
break;
case 6:
#line 213 "parser/yacc/gramatica.y"
	{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funrec_base_def ---> palavra '(' varspre DIGITO ')'\" foi reconhecido!\n");
					printf("[DEBUG] * palavra  : {%s}\n",palavra);
					printf("[DEBUG] * varspre: (");var_print(vars);printf(")\n");
					printf("[DEBUG] * DIGITO   : {%u}\n",yystack.l_mark[-1].natural);
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				if (yystack.l_mark[-1].natural != 0)
				{
					ERRO_RECURSAO_NAO_ZERO(palavra,0,yystack.l_mark[-1].natural);
					YYABORT;
				}
				/* A variável mais a direita (a variável da recursão) desta função será salva como zero (pois este é o CASO BASE).*/
				/* Se uma função idêntica (mas que define o PASSO da recursão) for reconhecida, este zero será trocado pelo*/
				/* nome correto da variável da recursão. Na verdade, a função "montar_recursao()" do arquivo "fileparser.h"*/
				/* unirá o nó BASE e o nó PASSO em um só nó com a definição completa da recursão.*/
				if (!var_append('0'))
				{
					ERRO_RECURSAO_MAX_ARGUMENTOS(palavra,VALORES_TAMANHO);
					YYABORT;
				}
				/* Checar se a definição de função lida é uma das funções primitivas:*/
				if (funcao_Z_S_GERAL(palavra,vars) != GENERAL_FUNCTION)
				{
					ERRO_FUNCAO_BASICA(palavra);
					YYABORT;
				}
				/* Alocar novo nó (sem tipo ainda):*/
				no = fundef_novo(palavra,vars);
			}
break;
case 8:
#line 251 "parser/yacc/gramatica.y"
	{ implaux_append(funimpl_novo_constante(valoraux)); }
break;
case 9:
#line 259 "parser/yacc/gramatica.y"
	{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funrec_passo_def ---> palavra '(' vars '+' DIGITO ')'\" foi reconhecido!\n");
					printf("[DEBUG] * palavra : {%s}\n",palavra);
					printf("[DEBUG] * vars    : (");var_print(vars);printf(")\n");
					printf("[DEBUG] * DIGITO  : {%u}\n",yystack.l_mark[-1].natural);
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				if (yystack.l_mark[-1].natural != 1)
				{
					ERRO_RECURSAO_NAO_ZERO(palavra,1,yystack.l_mark[-1].natural);
					YYABORT;
				}
				/* Checar se a definição de função lida é uma das funções primitivas:*/
				if (funcao_Z_S_GERAL(palavra,vars) != GENERAL_FUNCTION)
				{
					ERRO_FUNCAO_BASICA(palavra);
					YYABORT;
				}
				setstring(&(funrec_passo_def[0]),palavra);
				setstring(&(funrec_passo_def[1]),vars);
				linkedlist_push_string(&listalixo,funrec_passo_def[0]);
				linkedlist_push_string(&listalixo,funrec_passo_def[1]);
			}
break;
case 10:
#line 289 "parser/yacc/gramatica.y"
	{
				/* --- Casos ---------------------------------------*/
				/* * (...) = G(t, H(x1, ..., xn, t), x1, ..., xn)*/
				/* * (...) = G(t, H(t))*/
				/* -------------------------------------------------*/
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funrec_passo_impl ---> funnome '(' VARNOME ',' fundef varspos ')'\" foi reconhecido!\n");
					printf("[DEBUG] * Recursao:\n");
					printf("[DEBUG]   + nome : {%s}\n",no->nome);
					printf("[DEBUG]   + vars : (");var_print(no->variaveis);printf(")\n");
					printf("[DEBUG] * Passo (partes):\n");
					printf("[DEBUG]   + nome    : {%s}\n",funnome_ultimo);
					printf("[DEBUG]   + VARNOME : {%c}\n",yystack.l_mark[-4].caractere);
					printf("[DEBUG]   + varspos : (");var_print(vars);printf(")\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* Backup das variáveis da função Passo (da 3ª em diante):*/
				char *var_backup = NULL;
				setstring(&var_backup,vars);
				linkedlist_push_string(&listalixo,var_backup);
				/* Adicionar variável da recursão a lista de variáveis da função Passo (para checar se ela está repetida):*/
				if (!var_append(yystack.l_mark[-4].caractere))
				{
					ERRO_ARGUMENTO_DUPLICADO(yystack.l_mark[-4].caractere,funnome_ultimo);
					YYABORT;
				}
				/* Checar se a quantidade de variáveis do função Passo extrapolou o máximo permitido*/
				/* O +1 equivale ao espaço da função H(..) que será argumento para a função G(...):*/
				if (strlen(vars)+1 > VALORES_TAMANHO)
				{
					ERRO_RECURSAO_MAX_ARGUMENTOS(funnome_ultimo,VALORES_TAMANHO);
					YYABORT;
				}
				/* Checar se as variáveis da função Recursao e da função Passo são iguais:*/
				if (strcmp(no->variaveis,vars))
				{
					ERRO_ARGUMENTOS_DIFERENTES(no->nome,funnome_ultimo);
					YYABORT;
				}
				/* Montagem das variáveis da função Passo:*/
				reset_vars();
				var_append(yystack.l_mark[-4].caractere);
				var_append(VARS_PLACEHOLDER);
				unsigned int i;
				for (i=0 ; i<strlen(var_backup) ; i++) var_append(var_backup[i]);
				/* Verificar se o valor do índice "n" da Projeção é igual a quantidade de variáveis:*/
				if (projecao_indice(yystack.l_mark[-6].fnome,strlen(vars)))
				{
					ERRO_PROJECAO_LIMITE_ARIDADE(yystack.l_mark[-6].fnome.projecao.n,strlen(vars));
					YYABORT;
				}
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("[DEBUG] * Passo (montado):\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				implauxtemp = gerar_funimpl(yystack.l_mark[-6].fnome);
				/* Montar a struct da recursão (com o passo apenas):*/
				no->implementacao = funimpl_novo_recursao(no,fundef_aridade(no),implauxtemp,RECURSAO_PASSO);
			}
break;
case 11:
#line 350 "parser/yacc/gramatica.y"
	{ reset_vars(); }
break;
case 13:
#line 356 "parser/yacc/gramatica.y"
	{ reset_vars(); }
break;
case 15:
#line 362 "parser/yacc/gramatica.y"
	{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"fundef ---> palavra '(' vars ')'\" foi reconhecido!\n");
					printf("[DEBUG] * palavra: {%s}\n",palavra);
					printf("[DEBUG] * vars   : (");var_print(vars);printf(")\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* Checar se a definição de função lida é uma das funções primitivas:*/
				if (funcao_Z_S_GERAL(palavra,vars) != GENERAL_FUNCTION)
				{
					ERRO_FUNCAO_BASICA(palavra);
					YYABORT;
				}
				/* Alocar novo nó (sem tipo ainda):*/
				no = fundef_novo(palavra,vars);
				reset_palavra();
			}
break;
case 16:
#line 385 "parser/yacc/gramatica.y"
	{
				#ifdef DEBUG_FUNCTIONPARSER_GRAMATICA
					printf("\n[DEBUG] Um \"funimpl ---> funnome '(' vars ')'\" foi reconhecido!\n");
				#endif /*DEBUG_FUNCTIONPARSER_GRAMATICA*/
				/* Verificar se o valor do índice "n" da Projeção é igual a quantidade de variáveis:*/
				if (projecao_indice(yystack.l_mark[-3].fnome,strlen(vars)))
				{
					ERRO_PROJECAO_LIMITE_ARIDADE(yystack.l_mark[-3].fnome.projecao.n,strlen(vars));
					YYABORT;
				}
				implauxtemp = gerar_funimpl(yystack.l_mark[-3].fnome);
				/* Adicionar a implementação lida ao vetor de implementações:*/
				if (!implaux_append(implauxtemp))
				{
					funimpl_del(implauxtemp);
					ERRO_IMPLEMENTACOES_MAXIMO(VALORES_TAMANHO);
					YYABORT;
				}
			}
break;
case 19:
#line 416 "parser/yacc/gramatica.y"
	{
				yyval.fnome.tipo = -1;
				setstring(&(yyval.fnome.nome),palavra);
				linkedlist_push_string(&listalixo,yyval.fnome.nome);
				funnome_ultimo = yyval.fnome.nome;
			}
break;
case 20:
#line 426 "parser/yacc/gramatica.y"
	{
				/* Verificar se o nome da Projeção é "U":*/
				if (yystack.l_mark[-4].caractere != 'U')
				{
					ERRO_PROJECAO_NOME(yystack.l_mark[-4].caractere);
					YYABORT;
				}
				if ((yystack.l_mark[-2].natural < 1) || (yystack.l_mark[-2].natural > yystack.l_mark[0].natural))
				{
					ERRO_PROJECAO_INDICE(yystack.l_mark[-2].natural,yystack.l_mark[0].natural);
					YYABORT;
				}
				yyval.fnome.tipo = PROJECTION_FUNCTION;
				/* --- Nome da função ------------------------------------------------------------------------*/
				reset_palavra();
				palavra_append(yystack.l_mark[-4].caractere);
				palavra_append('_');
				palavra_append_num(yystack.l_mark[-2].natural);
				palavra_append('_');
				palavra_append_num(yystack.l_mark[0].natural);
				setstring(&(yyval.fnome.projecao.nome),palavra);
				/* Guardar referência‎ para desalocação futura:*/
				linkedlist_push_string(&listalixo,yyval.fnome.projecao.nome);
				funnome_ultimo = yyval.fnome.projecao.nome;
				/* -------------------------------------------------------------------------------------------*/
				yyval.fnome.projecao.i = yystack.l_mark[-2].natural;
				yyval.fnome.projecao.n = yystack.l_mark[0].natural;
			}
break;
case 21:
#line 458 "parser/yacc/gramatica.y"
	{ reset_palavra(); palavra_append(yystack.l_mark[0].caractere); }
break;
case 22:
#line 460 "parser/yacc/gramatica.y"
	{ palavra_append(yystack.l_mark[0].caractere); }
break;
case 23:
#line 465 "parser/yacc/gramatica.y"
	{ reset_vars(); var_append(yystack.l_mark[0].caractere); }
break;
case 24:
#line 467 "parser/yacc/gramatica.y"
	{
				if (!var_append(yystack.l_mark[0].caractere))
				{
					if (strlen(palavra))
						ERRO_ARGUMENTO_DUPLICADO(yystack.l_mark[0].caractere,palavra);
					else
						ERRO_ARGUMENTO_DUPLICADO(yystack.l_mark[0].caractere,funnome_ultimo);
					YYABORT;
				}
			}
break;
case 25:
#line 481 "parser/yacc/gramatica.y"
	{ yyval.natural = yystack.l_mark[0].natural; }
break;
case 26:
#line 483 "parser/yacc/gramatica.y"
	{ yyval.natural = yystack.l_mark[-1].natural * 10 + yystack.l_mark[0].natural; }
break;
case 27:
#line 488 "parser/yacc/gramatica.y"
	{ valoraux = yystack.l_mark[0].natural; }
break;
case 28:
#line 490 "parser/yacc/gramatica.y"
	{ valoraux = valoraux * 10 + yystack.l_mark[0].natural; }
break;
#line 1079 "parser/functionparser.c"
    }
    yystack.s_mark -= yym;
    yystate = *yystack.s_mark;
    yystack.l_mark -= yym;
    yym = yylhs[yyn];
    if (yystate == 0 && yym == 0)
    {
#if YYDEBUG
        if (yydebug)
            printf("%sdebug: after reduction, shifting from state 0 to\
 state %d\n", YYPREFIX, YYFINAL);
#endif
        yystate = YYFINAL;
        *++yystack.s_mark = YYFINAL;
        *++yystack.l_mark = yyval;
        if (yychar < 0)
        {
            if ((yychar = YYLEX) < 0) yychar = 0;
#if YYDEBUG
            if (yydebug)
            {
                yys = yyname[YYTRANSLATE(yychar)];
                printf("%sdebug: state %d, reading %d (%s)\n",
                        YYPREFIX, YYFINAL, yychar, yys);
            }
#endif
        }
        if (yychar == 0) goto yyaccept;
        goto yyloop;
    }
    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
        yystate = yytable[yyn];
    else
        yystate = yydgoto[yym];
#if YYDEBUG
    if (yydebug)
        printf("%sdebug: after reduction, shifting from state %d \
to state %d\n", YYPREFIX, *yystack.s_mark, yystate);
#endif
    if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack))
    {
        goto yyoverflow;
    }
    *++yystack.s_mark = (short) yystate;
    *++yystack.l_mark = yyval;
    goto yyloop;

yyoverflow:
    yyerror("yacc stack overflow");

yyabort:
    yyfreestack(&yystack);
    return (1);

yyaccept:
    yyfreestack(&yystack);
    return (0);
}
